#include "SWFTreeModel.h"
#include "swf/abc/AS3Model.h"
#include <QtGui>
#include "DoABCTreeItem.h"
#include "TagTreeItem.h"

SWFTreeModel::SWFTreeModel(QObject *parent)
	: QAbstractItemModel(parent)
{
	_rootItem = new SWFTreeItem("Title");
	_rootItem->_model = this;

	_headerStringList << "Title";
}

SWFTreeModel::~SWFTreeModel()
{
	delete _rootItem;
}

int SWFTreeModel::columnCount(const QModelIndex &parent) const
{
	return _headerStringList.size();
	if (parent.isValid())
		return static_cast<SWFTreeItem*>(parent.internalPointer())->columnCount();
	else
		return _rootItem->columnCount();
}

QVariant SWFTreeModel::data(const QModelIndex &index, int role) const
{
	if (!index.isValid())
		return QVariant();

	SWFTreeItem *item = static_cast<SWFTreeItem*>(index.internalPointer());

	return item->data(index.column(), role);
}

Qt::ItemFlags SWFTreeModel::flags(const QModelIndex &index) const
{
	if (!index.isValid())
		return 0;

	return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}

QModelIndex SWFTreeModel::index(int row, int column, const QModelIndex &parent)
	const
{
	if (!hasIndex(row, column, parent))
		return QModelIndex();

	SWFTreeItem *parentItem;

	if (!parent.isValid())
		parentItem = _rootItem;
	else
		parentItem = static_cast<SWFTreeItem*>(parent.internalPointer());

	SWFTreeItem *childItem = parentItem->child(row);
	if (childItem)
		return createIndex(row, column, childItem);
	else
		return QModelIndex();
}

QModelIndex SWFTreeModel::parent(const QModelIndex &index) const
{
	if (!index.isValid())
		return QModelIndex();

	SWFTreeItem *childItem = static_cast<SWFTreeItem*>(index.internalPointer());
	SWFTreeItem *parentItem = childItem->parent();

	if (parentItem == _rootItem)
		return QModelIndex();

	return createIndex(parentItem->row(), 0, parentItem);
}

int SWFTreeModel::rowCount(const QModelIndex &parent) const
{
	SWFTreeItem *parentItem;
	if (parent.column() > 0)
		return 0;

	if (!parent.isValid())
		parentItem = _rootItem;
	else
		parentItem = static_cast<SWFTreeItem*>(parent.internalPointer());

	parentItem->beforeRequestChildCount();
	return parentItem->childCount();
}

void SWFTreeModel::appendRow( SWFTreeItem* item )
{
	beginResetModel();
	_rootItem->appendRow(item);
	endResetModel();
}

bool SWFTreeModel::hasChildren( const QModelIndex &parent /*= QModelIndex()*/ ) const 
{
	SWFTreeItem *parentItem;
	if (!parent.isValid())
		parentItem = _rootItem;
	else
		parentItem = static_cast<SWFTreeItem*>(parent.internalPointer());
	return parentItem->hasChildren();
}

SWFTreeItem* SWFTreeModel::itemFromIndex( const QModelIndex& index ) const
{
	if (!index.isValid())
		return nullptr;
	return static_cast<SWFTreeItem*>(index.internalPointer());
}

QVariant SWFTreeModel::headerData( int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole*/ ) const 
{
	QVariant V = QAbstractItemModel::headerData(section, orientation, role);
	if (role == Qt::DisplayRole)
	{
		V = QVariant(_headerStringList[section]);
	}
	return V;
}

void SWFTreeModel::setHeaderStringList( QStringList& list )
{
	this->_headerStringList = list;
}

//////////////////////////////////////////////////////////////////////////

SWFTreeItem::SWFTreeItem(const std::string& data)
	: _kind(SWFTreeItemKind::Unknow)
	, _dataPtr(nullptr)
{
	this->setData(QVariant(data.c_str()), Qt::DisplayRole);
}

SWFTreeItem::~SWFTreeItem()
{
	qDeleteAll(_childItems);
}

void SWFTreeItem::appendRow(SWFTreeItem *item)
{
	_childItems.append(item);
	item->_parentItem = this;
	item->_model = _model;
}

SWFTreeItem *SWFTreeItem::child(int row)
{
	return _childItems.value(row);
}

int SWFTreeItem::childCount() const
{
	return _childItems.count();
}

int SWFTreeItem::columnCount() const
{
	return 1;
}

QVariant SWFTreeItem::data(int column, int role) const
{
	auto itr = _varMap.find(column);
	if (itr == _varMap.end())
		return QVariant();
	auto roleMap = _varMap[column];
	auto itr2 = roleMap.find(role);

	return roleMap[role];
}

SWFTreeItem *SWFTreeItem::parent()
{
	return _parentItem;
}

int SWFTreeItem::row() const
{
	if (_parentItem)
		return _parentItem->_childItems.indexOf(const_cast<SWFTreeItem*>(this));

	return 0;
}

bool SWFTreeItem::hasChildren() const
{
	return _childItems.size() > 0;
}

void SWFTreeItem::beforeRequestChildCount()
{

}

void SWFTreeItem::setData( const QVariant& var, int role, int column )
{
	auto itr = _varMap.find(column);
	if (itr == _varMap.end())
		_varMap[column] = QMap<int, QVariant>();
	_varMap[column][role] = var;
}

QMenu* SWFTreeItem::requestContextMenu()
{
	return nullptr;
}

void SWFTreeItem::setName( const std::string& name )
{
	this->setData(name.c_str(), Qt::DisplayRole);
	this->setData(name.c_str(), Qt::ToolTipRole);
}

void SWFTreeItem::setName(const QString& name)
{
	this->setData(name, Qt::DisplayRole);
	this->setData(name, Qt::ToolTipRole);
}

void SWFTreeItem::setIcon( const QIcon& icon )
{
	this->setData(icon, Qt::DecorationRole);
}

//////////////////////////////////////////////////////////////////////////
SWFItem::SWFItem( AS3SWF* as3swf )
	: _as3swf(as3swf)
{
	this->setName(as3swf->getFileInfo().fileName());

	std::vector<AS3ABCFile*> abcVec;
	as3swf->getAllABCFiles(abcVec);
	std::vector<AS3Class*> allClasses;
	for (auto abc : abcVec)
	{
		abc->getAllClasses(allClasses);
	}

	auto item = new SWFTreeItem("Classes");
	for (auto clazz : allClasses)
	{
		auto child = new SWFClassItem(clazz);
		item->appendRow(child);
	}
	this->appendRow(item);
	std::vector<SWFTagWrapper*> tags;
	//Images
	as3swf->getImageTags(tags);
	item = new SWFTreeItem("Images");
	for (SWFTagWrapper* tag : tags)
	{
		item->appendRow(new TagTreeItem(tag));
	}
	this->appendRow(item);
	tags.clear();

	//shapes
	as3swf->getShapeTags(tags);
	item = new SWFTreeItem("Shapes");
	for (SWFTagWrapper* tag : tags)
	{
		item->appendRow(new TagTreeItem(tag));
	}
	this->appendRow(item);
	tags.clear();

	//Sprite
	as3swf->getSpriteTags(tags);
	item = new SWFTreeItem("Sprites");
	for (SWFTagWrapper* tag : tags)
	{
		item->appendRow(new TagTreeItem(tag));
	}
	this->appendRow(item);
	tags.clear();

	//Texts
	as3swf->getTextTags(tags);
	item = new SWFTreeItem("Texts");
	for (SWFTagWrapper* tag : tags)
	{
		item->appendRow(new TagTreeItem(tag));
	}
	this->appendRow(item);
	tags.clear();

	//buttons
	as3swf->getButtonTags(tags);
	item = new SWFTreeItem("Buttons");
	for (SWFTagWrapper* tag : tags)
	{
		item->appendRow(new TagTreeItem(tag));
	}
	this->appendRow(item);
	tags.clear();

	//Others
	as3swf->getOtherTags(tags);
	item = new SWFTreeItem("Others");
	for (SWFTagWrapper* tag : tags)
	{
		item->appendRow(new TagTreeItem(tag));
	}
	this->appendRow(item);
	tags.clear();
}
